﻿using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Rendering;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices;
using System.Security.Principal;
using Urs.Admin.Models.Common;
using Urs.Core;
using Urs.Core.Caching;
using Urs.Core.Infrastructure;
using Urs.Core.Plugins;
using Urs.Data.Domain.Configuration;
using Urs.Services.Configuration;
using Urs.Services.Users;
using Urs.Services.Directory;
using Urs.Services.Localization;
using Urs.Services.Orders;
using Urs.Services.Payments;
using Urs.Services.Security;
using Urs.Services.Shipping;
using Urs.Framework.Controllers;
using Urs.Framework.Security;

namespace Urs.Admin.Controllers
{
    [AdminAuthorize]
    public partial class CommonController : BaseAdminController
    {
        #region Fields

        private readonly IPaymentService _paymentService;
        private readonly IShippingService _shippingService;
        private readonly IShoppingCartService _shoppingCartService;
        private readonly IMeasureService _measureService;
        private readonly IUserService _userService;
        private readonly IWebHelper _webHelper;
        private readonly StoreInformationSettings _storeInformationSettings;
        private readonly MeasureSettings _measureSettings;
        private readonly IWorkContext _workContext;
        private readonly IPermissionService _permissionService;
        private readonly ILocalizationService _localizationService;
        private readonly IAreaService _areaService;
        private readonly ISettingService _settingService;
        private readonly OrderSettings _orderSettings;
        private readonly IUrsFileProvider _fileProvider;
        private readonly ICacheManager _cacheManager;

        #endregion

        #region Constructors

        public CommonController(IPaymentService paymentService, IShippingService shippingService,
            IShoppingCartService shoppingCartService,
            IMeasureService measureService,IUserService userService,IWebHelper webHelper,
            StoreInformationSettings storeInformationSettings,
            MeasureSettings measureSettings,
             IWorkContext workContext,
            IPermissionService permissionService, ILocalizationService localizationService,
            IAreaService areaService,
            ISettingService settingService,
            OrderSettings orderSettings,
            IUrsFileProvider fileProvider,
            ICacheManager cacheManager)
        {
            this._paymentService = paymentService;
            this._shippingService = shippingService;
            this._shoppingCartService = shoppingCartService;
            this._measureService = measureService;
            this._userService = userService;
            this._webHelper = webHelper;
            this._storeInformationSettings = storeInformationSettings;
            this._measureSettings = measureSettings;
            this._workContext = workContext;
            this._permissionService = permissionService;
            this._localizationService = localizationService;
            this._areaService = areaService;
            this._settingService = settingService;
            this._orderSettings = orderSettings;
            this._fileProvider = fileProvider;
            this._cacheManager = cacheManager;
        }

        #endregion

        #region Methods

        public IActionResult SystemInfo()
        {
            var model = new SystemInfoModel();
            model.UrsVersion = UrsVersion.CurrentVersion;
            try
            {
                model.OperatingSystem = Environment.OSVersion.VersionString;
            }
            catch (Exception) { }
            try
            {
                model.AspNetInfo = RuntimeEnvironment.GetSystemVersion();
            }
            catch (Exception) { }
            try
            {
                model.IsFullTrust = AppDomain.CurrentDomain.IsFullyTrusted.ToString();
            }
            catch (Exception) { }
            model.ServerTimeZone =  TimeZone.CurrentTimeZone.StandardName;
            model.ServerLocalTime = DateTime.Now;
            model.UtcTime = DateTime.Now;
            foreach (var assembly in AppDomain.CurrentDomain.GetAssemblies())
            {
                model.LoadedAssemblies.Add(new SystemInfoModel.LoadedAssembly()
                {
                    FullName = assembly.FullName,
                    //we cannot use Location property in medium trust
                    //Location = assembly.Location
                });
            }
            return View(model);
        }

        public IActionResult Warnings()
        {
            var model = new List<SystemWarningModel>();

            //store URL
            if (!String.IsNullOrEmpty(_storeInformationSettings.StoreUrl) &&
                (_storeInformationSettings.StoreUrl.Equals(_webHelper.GetStoreLocation(false), StringComparison.InvariantCultureIgnoreCase)
                ||
                _storeInformationSettings.StoreUrl.Equals(_webHelper.GetStoreLocation(true), StringComparison.InvariantCultureIgnoreCase)
                ))
                model.Add(new SystemWarningModel()
                {
                    Level = SystemWarningLevel.Pass,
                    Text = _localizationService.GetResource("Admin.System.Warnings.URL.Match")
                });
            else
                model.Add(new SystemWarningModel()
                {
                    Level = SystemWarningLevel.Warning,
                    Text = string.Format(_localizationService.GetResource("Admin.System.Warnings.URL.NoMatch"), _storeInformationSettings.StoreUrl, _webHelper.GetStoreLocation(false))
                });

            //base measure weight
            var bWeight = _measureService.GetMeasureWeightById(_measureSettings.BaseWeightId);
            if (bWeight != null)
            {
                model.Add(new SystemWarningModel()
                {
                    Level = SystemWarningLevel.Pass,
                    Text = _localizationService.GetResource("Admin.System.Warnings.DefaultWeight.Set"),
                });

                if (bWeight.Ratio != 1)
                {
                    model.Add(new SystemWarningModel()
                    {
                        Level = SystemWarningLevel.Fail,
                        Text = _localizationService.GetResource("Admin.System.Warnings.DefaultWeight.Ratio1")
                    });
                }
            }
            else
            {
                model.Add(new SystemWarningModel()
                {
                    Level = SystemWarningLevel.Fail,
                    Text = _localizationService.GetResource("Admin.System.Warnings.DefaultWeight.NotSet")
                });
            }


            //base dimension weight
            var bDimension = _measureService.GetMeasureDimensionById(_measureSettings.BaseDimensionId);
            if (bDimension != null)
            {
                model.Add(new SystemWarningModel()
                {
                    Level = SystemWarningLevel.Pass,
                    Text = _localizationService.GetResource("Admin.System.Warnings.DefaultDimension.Set"),
                });

                if (bDimension.Ratio != 1)
                {
                    model.Add(new SystemWarningModel()
                    {
                        Level = SystemWarningLevel.Fail,
                        Text = _localizationService.GetResource("Admin.System.Warnings.DefaultDimension.Ratio1")
                    });
                }
            }
            else
            {
                model.Add(new SystemWarningModel()
                {
                    Level = SystemWarningLevel.Fail,
                    Text = _localizationService.GetResource("Admin.System.Warnings.DefaultDimension.NotSet")
                });
            }

            //shipping rate coputation methods
            if (_shippingService.LoadActiveShippingRateComputationMethods()
                .Where(x => x.ShippingRateMethodType == ShippingRateMethodType.Offline)
                .Count() > 1)
                model.Add(new SystemWarningModel()
                {
                    Level = SystemWarningLevel.Warning,
                    Text = _localizationService.GetResource("Admin.System.Warnings.Shipping.OnlyOneOffline")
                });

            //payment methods
            if (_paymentService.LoadActivePaymentMethods()
                .Count() > 0)
                model.Add(new SystemWarningModel()
                {
                    Level = SystemWarningLevel.Pass,
                    Text = _localizationService.GetResource("Admin.System.Warnings.PaymentMethods.OK")
                });
            else
                model.Add(new SystemWarningModel()
                {
                    Level = SystemWarningLevel.Fail,
                    Text = _localizationService.GetResource("Admin.System.Warnings.PaymentMethods.NoActive")
                });

            //incompatible plugins
            if (PluginManager.IncompatiblePlugins != null)
                foreach (var pluginName in PluginManager.IncompatiblePlugins)
                    model.Add(new SystemWarningModel()
                    {
                        Level = SystemWarningLevel.Warning,
                        Text = string.Format(_localizationService.GetResource("Admin.System.Warnings.IncompatiblePlugin"), pluginName)
                    });

            //validate write permissions (the same procedure like during installation)
            var dirPermissionsOk = true;
            var dirsToCheck = FilePermissionHelper.GetDirectoriesWrite(_webHelper);
            foreach (string dir in dirsToCheck)
                if (!FilePermissionHelper.CheckPermissions(dir, false, true, true, false))
                {
                    model.Add(new SystemWarningModel()
                    {
                        Level = SystemWarningLevel.Warning,
                        Text = string.Format(_localizationService.GetResource("Admin.System.Warnings.DirectoryPermission.Wrong"), WindowsIdentity.GetCurrent().Name, dir)
                    });
                    dirPermissionsOk = false;
                }
            if (dirPermissionsOk)
                model.Add(new SystemWarningModel()
                {
                    Level = SystemWarningLevel.Pass,
                    Text = _localizationService.GetResource("Admin.System.Warnings.DirectoryPermission.OK")
                });

            var filePermissionsOk = true;
            var filesToCheck = FilePermissionHelper.GetFilesWrite(_webHelper);
            foreach (string file in filesToCheck)
                if (!FilePermissionHelper.CheckPermissions(file, false, true, true, true))
                {
                    model.Add(new SystemWarningModel()
                    {
                        Level = SystemWarningLevel.Warning,
                        Text = string.Format(_localizationService.GetResource("Admin.System.Warnings.FilePermission.Wrong"), WindowsIdentity.GetCurrent().Name, file)
                    });
                    filePermissionsOk = false;
                }
            if (filePermissionsOk)
                model.Add(new SystemWarningModel()
                {
                    Level = SystemWarningLevel.Pass,
                    Text = _localizationService.GetResource("Admin.System.Warnings.FilePermission.OK")
                });


            return View(model);
        }

        public JsonResult ProvincesSelector(string selectedValue)
        {
            var list = _areaService.GetProvinces().Select(p =>
            {
                return new SelectListItem { Text = p, Value = p };
            });

            return Json(new SelectList(list,"Value", "Text",selectedValue));
        }

        public JsonResult CitiesSelector(string provincename)
        {
            var list = _areaService.GetCities(provincename).Select(p =>
            {
                return new SelectListItem { Text = p, Value = p };
            });
            return Json(new SelectList(list, "Value", "Text"));
        }

        public JsonResult AreasSelector(string provincename, string cityname)
        {
            var list = _areaService.GetAreas(provincename, cityname).Select(p =>
            {
                return new SelectListItem { Text = p, Value = p };
            });
            return Json(new SelectList(list, "Value", "Text"));
        }

        public IActionResult ClearCache()
        {
            if (!_permissionService.Authorize(StandardPermissionProvider.AccessAdminPanel))
                return HttpUnauthorized();

            _cacheManager.Clear();

            return RedirectToAction("Index", "Home");
        }

        public IActionResult RestartApplication()
        {
            if (!_permissionService.Authorize(StandardPermissionProvider.AccessAdminPanel))
                return HttpUnauthorized();

            //restart application
            _webHelper.RestartAppDomain();
            return RedirectToAction("Index", "Home");
        }

        #endregion
    }
}
